import { Element, ContextElement, findLastDom, InputElement, LabelElement, SplitElement, ElementType, ElementFactoryMap as ElementFactory, NextLineElement, MainElement } from './elements';
import { LinkedListNode, LinkedList, NodeCursor } from '../common/linked_list';
import { TokenService, Command, InputUpdateRequest, Location, Range, NextLineRequest, Position } from '../protocol/token.service';
import { DefaultDomController, InputDomController, NextLineDomController } from './dom_controller';

interface ElementsStore {
  appendElement: <T extends Element>(
    element: T,
    parent: ContextElement | undefined,
    prev: LinkedListNode<Element> | undefined,
    dom: HTMLElement | undefined
  ) => LinkedListNode<T>;
  removeElement: (startPosition: Position, range: Range) => LinkedListNode<Element> | undefined;
  getElementLocation: (element: MainElement) => Location;
  getNodesByLocation: (location: Location) => LinkedListNode<Element>[];
  getChildAtOffset: (element: ContextElement | undefined, offset: number) => LinkedListNode<Element>;
  offsetNode: (node: LinkedListNode<Element>, offset: number) => LinkedListNode<Element>;
  offsetLocation: (location: Location, offset: number) => Location;
  focusThisElement: (location: Location, offset: number) => void;
  registerDomFactory: <A extends ElementType>(type: A, factory: ElementFactory[A]) => void;
}

/**
 * 创建编辑器elements相关状态操作
 * @returns elements相关操作
 */
export const createElementsStore = (contentArea: HTMLElement): ElementsStore => {
  const elements: LinkedList<Element> = new LinkedList();
  const domFactory: ElementFactory = {};

  const getElementInList = (element: Element) => {
    const parent = element.parentElement;
    return parent ? parent.children : elements;
  }

  const getElementLocation = (element: InputElement | ContextElement): Location => {
    const key = element.key;
    let parent = element.parentElement;
    if (parent) {
      const location = getElementLocation(parent);
      location.push(key);
      return location;
    } else {
      return [key];
    }
  }

  const offsetNode = (node: LinkedListNode<Element>, offset: number): LinkedListNode<Element> => {
    while (offset > 0) {
      offset--;
      node = node.next!;
    }
    return node;
  }

  const offsetLocation = (location: Location, offset: number): Location => {
    let node = getNodeByLocation(location);
    while (offset > 0) {
      offset--;
      node = node.next!;
    }
    const ret = location.slice(0, -1);
    ret.push(node.key!);
    return ret;
  }

  const getChildAtOffset = (element: ContextElement | undefined, offset: number): LinkedListNode<Element> => {
    let node = (element ? element.children : elements).getHead()!;
    while (offset > 1) {
      offset--;
      node = node.next!;
    }
    return node;
  }

  /**
   * 添加元素到编辑器
   * @param element 要添加的元素
   * @param parent 父元素（可选）
   * @param prev 前一个元素（可选）
   * @param dom 添加元素所在的dom位置（可选）
   * @returns 添加的元素
   */
  const appendElement = <T extends Element>(
    element: T,
    parent: ContextElement | undefined,
    prev: LinkedListNode<Element> | undefined,
    dom: HTMLElement | undefined  
  ): LinkedListNode<T> => {
    const type = element.type;
    element.parentElement = parent;
    const children = parent ? parent.children : elements;

    let node;
    if (type === 'input' || type === 'context') {
      node = children.setAfter(element.key, element, prev);
    } else {
      node = children.insertAfter(element, prev);
    }
    
    const func = domFactory[type];
    if (!func) {
      throw new Error("create element dom failed, element dom factory not exist")
    }
    const domController = func(element as any);
    element.dom = domController;
    if (!domController) {
      return node as LinkedListNode<T>;
    }
    
    if (dom) {
      domController.appendTo(dom);
    } else {
      domController.appendChildTo(contentArea);
    }
    return node as LinkedListNode<T>;
  }

  /**
   * 根据位置查找元素
   * @param location 位置
   * @param offset 偏移量，默认为0，正数表示向后偏移，负数表示向前偏移
   * @returns 查找到的元素节点
   */
  const findElementByLocation = (location: Location, offset: number): LinkedListNode<Element> => {
    let children = elements;
    let element: ContextElement | undefined = undefined;

    for (let i = 0; i < location.length - 1; i++) {
      const loc = location[i];
      const node = children.getNode(loc);
      if (!node) {
        throw new Error('find parent element failed, element not found');
      }
      const e = node.value;
      if (e.type !== 'context') {
        throw new Error('find parent element failed, element not context element');
      }
      element = e;
      children = e.children;
    }

    const lastIndex = location[location.length - 1];
    const lastNode = element ? element.children.getNode(lastIndex) : elements.getNode(lastIndex);
    if (!lastNode) {
      throw new Error('find last element failed, element not found');
    }
    
    // 处理偏移量
    let resultNode = lastNode;
    // 如果偏移量不为0，根据偏移量向前或向后查找
    while (offset !== 0) {
      if (offset > 0) {
        // 向后查找
        if (!resultNode.next) {
          throw new Error('offset exceeds the boundary, next element not found');
        }
        resultNode = resultNode.next;
        offset--;
      } else {
        // 向前查找
        if (!resultNode.prev) {
          throw new Error('offset exceeds the boundary, previous element not found');
        }
        resultNode = resultNode.prev;
        offset++;
      }
    }
    
    return resultNode;
  };

  /**
   * 删除元素的DOM
   * @param startNode 开始节点
   * @param range 删除范围，前闭后闭
   */
  const deleteElementDom = (startNode: LinkedListNode<Element>, range: Range) => {
    let currentNode: LinkedListNode<Element> | null = startNode;

    const nodeList = new NodeCursor(currentNode).getNodeList(range.start, range.end + 1);
    for (let j = 0; j < nodeList.length; j++) {
      const node = nodeList[j];
      const element = node.value;
      if (element.dom) {
        element.dom.remove();
        element.dom = undefined;
      }

      if (element.type === 'context') {
        const firstNode = element.children.getHead();
        if (firstNode) {
          deleteElementDom(firstNode, {
            start: 0,
            end: element.children.getLength() - 1
          });
        }
      }
    }
  }

  /**
   * 移除元素
   * @param startLocation 0点坐标
   * @param ranges 删除的范围
   * @returns 包含前一个DOM元素和当前被删除节点的对象
   */
  const removeElement = (startPosition: Position, range: Range): LinkedListNode<Element> | undefined => {
    let startNode: LinkedListNode<Element>;
    if (startPosition.moveToContext) {
      const children = startPosition.location.length === 0
        ? elements
        : (findElementByLocation(startPosition.location, 0).value as ContextElement).children;
      const head = children.getHead();
      if (!head) {
        throw new Error('remove element failed, context children is empty');
      }
      startNode = head;
      range = {
        start: range.start - 1,
        end: range.end
      };
    } else {
      startNode = findElementByLocation(startPosition.location, 0);
    }

    range = {
      start: range.start + startPosition.offset,
      end: range.end + startPosition.offset
    }

    // 获取父元素
    const items = getElementInList(startNode.value);
    // 删除DOM和数组元素
    deleteElementDom(startNode, range);

    // 删除element
    const cursor = new NodeCursor(startNode);
    cursor.go(range.start);
    const currentNode = cursor.getCurrentNode();
    const nodeList = cursor.moveToNext(range.end + 1);
    nodeList.forEach(node => items.removeNode(node));

    return currentNode.prev ? currentNode.prev : undefined;
  }

  const getElementNode = (element: MainElement): LinkedListNode<Element> => {
    const list = element.parentElement ? element.parentElement.children : elements;
    const node = list.getNode(element.key);
    if (!node) {
      throw new Error('element not found');
    }
    return node;
  }

  /**
   * 查找下一个输入元素
   * @param node 当前节点
   * @returns 找到的输入元素节点，如果没找到返回 null
   */
  const findNextInputElement = (node: LinkedListNode<Element>): LinkedListNode<Element> | null => {
    // 1. 先查找当前节点的下一个节点
    let nextNode = node.next;
    while (nextNode) {
      if (nextNode.value.type === 'input') {
        return nextNode;
      }
      // 如果是 context 类型，检查其 children 中是否有 input
      if (nextNode.value.type === 'context') {
        const firstNode = nextNode.value.children.getHead();
        if (firstNode) {
          if (firstNode.value.type === 'input') {
            return firstNode;
          }
          const found = findNextInputElement(firstNode);
          if (found) {
            return found;
          }
        }
      }
      nextNode = nextNode.next;
    }

    // 2. 如果当前层级没有下一个输入节点，则查找父节点的下一个节点
    const element = node.value;
    const parent = element.parentElement;
    if (!parent) {
      return null;
    }

    // 3. 直接通过 parent 的 index 获取对应的节点
    const parentNode = getElementNode(parent);
    return findNextInputElement(parentNode);
  }

  /**
   * 根据location获取node
   * @param location 位置
   * @returns 节点
   */
  const getNodeByLocation = (location: Location): LinkedListNode<Element> => {
    let children = elements;
    
    // 遍历位置数组，获取路径上所有的上下文节点
    for (let i = 0; i < location.length - 1; i++) {
      const loc = location[i];
      const node = children.getNode(loc);
      if (!node) {
        throw new Error('find parent element failed, element not found');
      }
      const e = node.value;
      if (e.type !== 'context') {
        break;
      }
      children = e.children;
    }
    return children.getNode(location[location.length - 1])!;
  }

  /**
   * 根据位置查找路径上所有的上下文节点
   * @param location 位置
   * @returns 路径上所有的上下文节点数组
   */
  const getNodesByLocation = (location: Location): LinkedListNode<Element>[] => {
    let children = elements;
    const result: LinkedListNode<Element>[] = [];
    
    // 遍历位置数组，获取路径上所有的上下文节点
    for (let i = 0; i < location.length; i++) {
      const loc = location[i];
      const node = children.getNode(loc);
      if (!node) {
        throw new Error('find parent element failed, element not found');
      }
      const e = node.value;

      result.push(node as LinkedListNode<Element>);
      if (e.type !== 'context') {
        break;
      }
      children = e.children;
    }
    return result;
  };

  const focusThisElement = (location: Location, offset?: number) => {
    let node = findElementByLocation(location, 0);
    if (offset) {
      node = offsetNode(node, offset);
    }
    if (node && node.value.dom) {
      node.value.dom.getMainDom().focus();
    }
  }

  /**
   * 查找上一个输入元素
   * @param node 当前节点
   * @returns 找到的输入元素节点，如果没找到返回 undefined
   */
  const findPrevInputElement = (node: LinkedListNode<Element>): LinkedListNode<Element> | undefined => {
    // 1. 先查找当前节点的上一个节点
    let prevNode = node.prev;
    while (prevNode) {
      if (prevNode.value.type === 'input') {
        return prevNode;
      }
      // 如果是 context 类型，检查其 children 中是否有 input
      if (prevNode.value.type === 'context') {
        const lastNode = prevNode.value.children.getTail();
        if (lastNode) {
          if (lastNode.value.type === 'input') {
            return lastNode;
          }
          const found = findPrevInputElement(lastNode);
          if (found) {
            return found;
          }
        }
      }
      prevNode = prevNode.prev;
    }

    // 2. 如果当前层级没有上一个输入节点，则查找父节点的上一个节点
    const element = node.value;
    const parent = element.parentElement;
    if (!parent) {
      return undefined;
    }

    // 3. 直接通过 parent 的 index 获取对应的节点
    const parentNode = getElementNode(parent);
    return findPrevInputElement(parentNode);
  }

  return {
    /**
     * 注册DOM工厂
     * @param type 元素类型
     * @param factory 工厂函数
     */
    registerDomFactory: <A extends ElementType>(type: A, factory: ElementFactory[A]) => {
      domFactory[type] = factory;
    },
    appendElement,
    removeElement,
    getElementLocation,
    offsetNode,
    offsetLocation,
    getChildAtOffset,
    getNodesByLocation,
    focusThisElement
  }
}

export class InputState {
  prevValue: string = '';
  // 当前值
  value: string = '';
  // 是否是编辑模式
  edit: boolean = false;
  // 输入框是否获取焦点
  inputFocus: boolean = false;
  // 是否输入法正在输入
  isComposition: boolean = false;
  // 候选词列表是否显示
  show: boolean = false;
  // 激活的候选词
  activeCandidate: string = '';
  // 激活的行
  activeLine: number = -1;
  // 候选词列表
  candidateList: Array<string> = [];
  // 是否在选择候选词
  selectingCandidate: boolean = false;
  // 菜单是否显示
  showMenu: boolean = false;
  // 菜单选项
  menuItems: Array<{ label: string, action: () => void }> = [];
  // 激活的菜单项
  activeMenuItem: number = -1;

  removing: boolean = false;

  constructor(value: string) {
    this.prevValue = value;
    this.value = value;
  }

  clear() {
    this.edit = false;
    this.inputFocus = false;
    this.isComposition = false;
    this.show = false;
    this.activeCandidate = '';
    this.activeLine = -1;
    this.candidateList = [];
    this.selectingCandidate = false;
    this.showMenu = false;
    this.activeMenuItem = -1;
    this.removing = false;
  }

  setActivedLine(line: number, activeCandidate: string) {
    this.activeLine = line;
    this.activeCandidate = activeCandidate;
  }

  setCandidateList(candidateList: Array<string>) {
    this.candidateList = candidateList;
    if (this.activeCandidate) {
      const newActiveLine = this.candidateList.indexOf(this.activeCandidate);
      this.activeLine = newActiveLine >= 0 ? newActiveLine : -1;
    } else {
      this.activeLine = -1;
    }
  }

  setMenuItems(items: Array<{ label: string, action: () => void }>) {
    this.menuItems = items;
    this.activeMenuItem = items.length > 0 ? 0 : -1;
  }

  setInputValue(value: string) {
    this.prevValue = this.value;
    this.value = value;
  }
}

interface InputService {
  sendComplete: (value: string, focusNext: boolean) => void;
  sendDelete: () => void;
  sendFocus: (element: InputElement) => void;
  queryCandidateList: (value: string) => Promise<Array<string>>;
  sendNextLine: () => void;
  sendEndContext: () => void;
}

const createInputService = (
  openedResourceId: string,
  tokenService: TokenService,
  editorStore: ElementsStore,
  element: InputElement
): InputService => {
  /**
   * 发送聚焦元素请求
   * @param location 元素所在的位置
   */
  const sendFocus = (element: InputElement) => {
    const location = editorStore.getElementLocation(element);
    tokenService.send(openedResourceId, [{
      type: 'focusElement',
      location: location
    }]).then((commandList) => {
      applyCommandList(editorStore, commandList);
    });
  }

  /**
   * 完成输入
   * @param focusNext 是否聚焦下一个元素
   */
  const sendComplete = (value: string, focusNext: boolean) => {
    const location = editorStore.getElementLocation(element);
    tokenService.send(openedResourceId, [{
      type: 'inputComplete',
      location,
      inputValue: value
    }]).then((commandList) => {
      const position = applyCommandList(editorStore, commandList);
      if (focusNext && position && (!position.moveToContext)) {
        editorStore.focusThisElement(position.location, position.offset);
      }
    });
  };

  /**
   * 删除输入
   */
  const sendDelete = () => {
    const location = editorStore.getElementLocation(element);
    tokenService.send(openedResourceId, [{
      type: 'delete',
      location,
    }]).then((commandList) => {
      const position = applyCommandList(editorStore, commandList);
      if (position && (!position.moveToContext)) {
        editorStore.focusThisElement(position.location, position.offset);
      }
    });
  }

  /**
   * 发送换行请求
   */
  const sendNextLine = () => {
    const location = editorStore.getElementLocation(element);
    const req: NextLineRequest = {
      type: 'nextLine',
      location: location
    };
    tokenService.send(openedResourceId, [req]).then((commandList) => {
      const position = applyCommandList(editorStore, commandList);
      if (position && (!position.moveToContext)) {
        editorStore.focusThisElement(position.location, position.offset);
      }
    });
  }

  /**
   * 发送结束context请求
   */
  const sendCompleteContext = () => {
    const location = editorStore.getElementLocation(element);
    tokenService.send(openedResourceId, [{
      type: 'completeContext',
      location
    }]).then((commandList) => {
      const position = applyCommandList(editorStore, commandList);
      if (position && (!position.moveToContext)) {
        editorStore.focusThisElement(position.location, position.offset);
      }
    });
  }

  /**
   * 查询候选词列表
   */
  const queryCandidateList = async (value: string) => {
    const req: InputUpdateRequest = {
      type: 'inputUpdate',
      inputValue: value,
      location: editorStore.getElementLocation(element)
    };
    return await tokenService.getCandidateTokens(openedResourceId, req);
  };

  return {
    sendComplete,
    sendDelete,
    sendFocus,
    queryCandidateList,
    sendNextLine,
    sendEndContext: sendCompleteContext
  }
}

/**
 * 创建 InputState 闭包
 * @param service input元素相关的后端服务
 * @param element 输入元素
 * @returns InputState 闭包函数
 */
export const createInputState = (
  service: InputService,
  element: InputElement
) => {
  const state = new InputState(element.inputValue);
  /**
   * 点击候选词
   * @param event 事件对象
   * @param candidate 候选词
   * @param line 行号
   */
  const onSelectCandidate = (event: Event, candidate: string, line: number) => {
    event.stopPropagation();
    state.setActivedLine(line, candidate);
    setShowState(false);

    state.setInputValue(candidate || '');
    const dom = element.dom!;
    const input = dom.querySelector('input') as HTMLInputElement;
    input.value = candidate || '';
    const inputLabel = dom.querySelector('.lfe-dsl-editor-input-label')!;
    inputLabel.textContent = candidate || '1';
    state.selectingCandidate = true;

    // 下一个宏任务执行focus，不然没法focus
    // selectingCandidate变量，可能存在并发问题，影响不大，暂不处理
    setTimeout(() => {
      input.focus();
    });
  };

  /**
   * 渲染候选词列表
   */
  const renderCandidateList = (state: InputState, candidateListDom: HTMLElement) => {
    candidateListDom.innerHTML = '';
    state.candidateList.forEach((label, index) => {
      const li = document.createElement('li');
      li.textContent = label;
      if (state.activeLine >= 0 && state.activeLine === index) {
        li.classList.add('active');
      }
      li.addEventListener('mousedown', (event) => {
        onSelectCandidate(event, label, index);
      });
      candidateListDom.appendChild(li);
    });
  };

  /**
   * 更新激活的行
   * @param originActiveLine 原激活行
   * @param newActiveLine 新激活行
   * @param candidateList 候选词列表
   */
  const changeActiveLine = (originActiveLine: number, newActiveLine: number, candidateList: Array<string>) => {
    if (originActiveLine === newActiveLine) {
      return;
    }
    state.setActivedLine(newActiveLine, candidateList[newActiveLine]);

    const candidateListDom = element.dom!.getMainDom().querySelector('.lfe-dsl-editor-input-candidate')! as HTMLElement;
    if (!candidateListDom) {
      return;
    }
    candidateListDom.querySelectorAll('li').forEach((li, index) => {
      if (index === originActiveLine) {
        li.classList.remove('active');
      }
      if (index === newActiveLine) {
        li.classList.add('active');
      }
    });
  };

  /**
   * 设置显示状态
   * @param newState 显示状态
   * @returns 是否改变状态
   */
  const setShowState = (newState: boolean) => {
    if (state.show !== newState) {
      state.show = newState;
      const candidateListDom = element.dom!.getMainDom().querySelector('.lfe-dsl-editor-input-candidate')! as HTMLElement;
      if (newState) {
        candidateListDom.classList.remove('hide');
        candidateListDom.classList.add('show-block');
      } else {
        candidateListDom.classList.remove('show-block');
        candidateListDom.classList.add('hide');
      }
    }
  };
  
  /**
   * 获取并且显示候选词列表
   */
  const queryAndShowCandidateList = async () => {
    setShowState(true);
    const currentValue = state.value;
    const candidateList = await service.queryCandidateList(currentValue);
    if (currentValue === state.value) {
      state.setCandidateList(candidateList);
      const candidateListDom = element.dom!.getMainDom().querySelector('.lfe-dsl-editor-input-candidate');
      if (!candidateListDom) {
        return;
      }
      renderCandidateList(state, candidateListDom as HTMLElement);
    }
  }

  /**
   * 聚焦元素
   */
  const focusElement = () => {
    if (state.edit) {
      return;
    }
    renderEdit();
    state.edit = true;
    const dom = element.dom!;
    dom.getMainDom().querySelector('input')!.focus();
  };

  /**
   * 整个元素失去焦点
   */
  const onBlur = () => {
    if (state.removing) {
      return;
    }
    state.clear();
    renderReadonly();
  };

  /**
   * 输入框获取焦点时的处理
   */
  const onFocusInput = async () => {
    state.inputFocus = true;
    if (state.selectingCandidate) {
      state.selectingCandidate = false;
    } else {
      service.sendFocus(element);
      queryAndShowCandidateList();
    }
  };

  /**
   * 输入框失去焦点
   */
  const onInputBlur = () => {
    // 清空dom时也会触发blur，state.inputFocus为true表示是正常失去焦点
    if (state.inputFocus) {
      state.inputFocus = false;
      if (!state.selectingCandidate) {
        onBlur();
      }
    }
  }

  /**
   * 处理输入法事件
   * @param ev 事件对象
   */
  const handleComposition = (ev: CompositionEvent) => {
    if (ev.type === 'compositionend') {
      state.isComposition = false;
    } else {
      state.isComposition = true;
    }
  };

  /**
   * 输入处理
   * @param inputValue 输入值
   */
  const input = (inputValue: string) => {
    state.setInputValue(inputValue);
    const inputLabel = element.dom!.getMainDom().querySelector('.lfe-dsl-editor-input-label')!;
    inputLabel.textContent = inputValue || '1';

    queryAndShowCandidateList();
  };

  /**
   * 创建只读输入框DOM
   * @returns 只读输入框DOM元素
   */
  const createReadonlyInputDom = (): HTMLElement => {
    const wrapper = document.createElement('div');
    wrapper.classList.add('lfe-dsl-editor-readonly-input-wrapper');
    wrapper.tabIndex = 0;

    const label = document.createElement('span');
    label.classList.add('lfe-dsl-editor-readonly-input-label');
    label.textContent = state.value;
    wrapper.addEventListener('click', () => {
      focusElement();
    });
    wrapper.addEventListener('focus', () => {
      focusElement();
    });
    wrapper.appendChild(label);
    return wrapper;
  };

  /**
   * 创建输入框DOM
   * @returns 输入框DOM元素
   */
  const createInputDom = () => {
    const wrapper = document.createElement('div');
    wrapper.classList.add('lfe-dsl-editor-input-wrapper');
    wrapper.addEventListener("keyup", handleKeyUp);
    wrapper.addEventListener("blur", onBlur);

    const inputBox = document.createElement('div');
    inputBox.classList.add('lfe-dsl-editor-input-box');
    wrapper.appendChild(inputBox);

    const input = document.createElement('input');
    input.type = 'text';
    input.value = state.value;
    input.classList.add('lfe-dsl-editor-input');
    input.addEventListener('input', onInput);
    input.addEventListener('compositionstart', handleComposition);
    input.addEventListener('compositionend', handleComposition);
    input.addEventListener('compositionupdate', handleComposition);
    input.addEventListener('focus', onFocusInput);
    input.addEventListener('blur', onInputBlur);

    inputBox.appendChild(input);

    const inputLabel = document.createElement('span');
    inputLabel.classList.add('lfe-dsl-editor-input-label');
    inputLabel.textContent = state.value || '1';
    inputBox.appendChild(inputLabel);

    const inputCandidate = document.createElement('ul');
    inputCandidate.classList.add('lfe-dsl-editor-input-candidate');
    wrapper.appendChild(inputCandidate);
    renderCandidateList(state, inputCandidate);

    const menu = document.createElement('div');
    menu.classList.add('lfe-dsl-editor-input-menu');
    menu.style.display = 'none';
    wrapper.appendChild(menu);
    renderMenu(state, menu);

    return wrapper;
  };

  /**
   * 渲染菜单
   */
  const renderMenu = (state: InputState, menu: HTMLElement) => {
    menu.innerHTML = '';
    if (!state.showMenu) {
      menu.style.display = 'none';
      return;
    }

    menu.style.display = 'block';
    state.menuItems.forEach((item, index) => {
      const menuItem = document.createElement('div');
      menuItem.classList.add('lfe-dsl-editor-input-menu-item');
      if (index === state.activeMenuItem) {
        menuItem.classList.add('active');
      }
      menuItem.textContent = item.label;
      menuItem.addEventListener('click', () => {
        item.action();
        state.showMenu = false;
        renderMenu(state, menu);
      });
      menu.appendChild(menuItem);
    });
  };

  /**
   * 处理菜单快捷键
   */
  const handleMenuKey = (e: KeyboardEvent) => {
    if (!state.showMenu) {
      return;
    }

    const key = e.key.toLowerCase();
    if (key === 'arrowdown') {
      e.preventDefault();
      const nextIndex = Math.min(state.menuItems.length - 1, state.activeMenuItem + 1);
      state.activeMenuItem = nextIndex;
      const dom = element.dom;
      if (!dom || Array.isArray(dom)) return;
      const menu = dom.querySelector('.lfe-dsl-editor-input-menu') as HTMLElement;
      renderMenu(state, menu);
    } else if (key === 'arrowup') {
      e.preventDefault();
      const prevIndex = Math.max(0, state.activeMenuItem - 1);
      state.activeMenuItem = prevIndex;
      const dom = element.dom;
      if (!dom || Array.isArray(dom)) return;
      const menu = dom.querySelector('.lfe-dsl-editor-input-menu') as HTMLElement;
      renderMenu(state, menu);
    } else if (key === 'enter') {
      e.preventDefault();
      if (state.activeMenuItem >= 0 && state.activeMenuItem < state.menuItems.length) {
        state.menuItems[state.activeMenuItem].action();
        state.showMenu = false;
        const dom = element.dom;
        if (!dom || Array.isArray(dom)) return;
        const menu = dom.querySelector('.lfe-dsl-editor-input-menu') as HTMLElement;
        renderMenu(state, menu);
      }
    } else if (key === 'escape') {
      e.preventDefault();
      state.showMenu = false;
      const dom = element.dom;
      if (!dom || Array.isArray(dom)) return;
      const menu = dom.querySelector('.lfe-dsl-editor-input-menu') as HTMLElement;
      renderMenu(state, menu);
    }
  };

  /**
   * 处理快捷键
   */
  const handleKeyUp = (e: KeyboardEvent) => {
    if (state.isComposition) {
      return;
    }

    if (state.showMenu) {
      handleMenuKey(e);
      return;
    }

    const key = e.key.toLowerCase();
    if (key === 'enter' && e.shiftKey) {
      e.preventDefault();
      state.showMenu = true;
      state.setMenuItems([
        {
          label: '结束上下文',
          action: () => {
            service.sendEndContext();
          }
        },
        {
          label: '换行',
          action: () => {
            console.log('换行');
          }
        },
        {
          label: '取消换行',
          action: () => {
            console.log('取消换行');
          }
        },
        {
          label: '增加缩进',
          action: () => {
            console.log('增加缩进');
          }
        },
        {
          label: '减少缩进',
          action: () => {
            console.log('减少缩进');
          }
        }
      ]);
      const dom = element.dom;
      if (!dom || Array.isArray(dom)) return;
      const menu = dom.querySelector('.lfe-dsl-editor-input-menu') as HTMLElement;
      renderMenu(state, menu);
      return;
    }

    if (key === 'enter') {
      if (state.show && state.activeLine >= 0) {
        onSelectCandidate(e, state.activeCandidate, state.activeLine);
        return;
      }
      if (state.inputFocus) {
        if (state.value === '') {
          state.clear();
          renderReadonly();
          setTimeout(() => {
            service.sendNextLine();
          });
        } else {
          state.clear();
          renderReadonly();
          setTimeout(() => {
            service.sendComplete(state.value, true);
          });
        }
      }
    } else if (key === 'backspace' && state.inputFocus) {
      if ((!state.value) && state.prevValue) {
        state.prevValue = state.value;
      } else if ((!state.value) && (!state.prevValue)) {
        service.sendDelete();
      }
    } else if (key === 'arrowdown') {
      if (state.candidateList.length > 0) {
        if (state.show) {
          const index = Math.min(state.candidateList.length - 1, state.activeLine + 1);
          changeActiveLine(state.activeLine, index, state.candidateList);
        } else {
          setShowState(true);
          if (state.activeLine < 0) {
            changeActiveLine(state.activeLine, 0, state.candidateList);
          }
        }
      }
    } else if (key === 'arrowup') {
      if (state.candidateList.length <= 0) {
        setShowState(false);
      } else if (state.show) {
        const index = state.activeLine - 1;
        if (index < 0) {
          setShowState(false);
        } else {
          changeActiveLine(state.activeLine, index, state.candidateList);
        }
      }
    } else if (key === 'escape') {
      setShowState(false);
    }
  };

  /**
   * 输入事件处理
   * @param e 事件对象
   */
  const onInput = (e: Event) => {
    const { value } = e.target as HTMLInputElement;
    input(value);
  };

  /**
   * 渲染只读状态
   */
  const renderReadonly = () => {
    const dom = element.dom!;
    const parentElement = dom.getMainDom().parentElement!;
    const newDom = new DefaultDomController(createReadonlyInputDom());
    element.dom = newDom;
    parentElement.replaceChild(newDom.getMainDom(), dom.getMainDom());
  };

  /**
   * 渲染编辑状态
   */
  const renderEdit = () => {
    const dom = element.dom!;
    const parentElement = dom.getMainDom().parentElement!;
    const newDom = new InputDomController(state, createInputDom());
    element.dom = newDom;
    parentElement.replaceChild(newDom.getMainDom(), dom.getMainDom());
    (newDom.querySelector('input') as HTMLInputElement).focus();
  };
  return { createReadonlyInputDom }
}

/**
 * 创建编辑器DOM
 * @param container 容器元素
 * @returns 编辑器DOM和移除加载遮罩的方法
 */
const createEditorDom = (container: HTMLElement): { editor: HTMLElement, contentArea: HTMLElement, removeLoadingMask: () => void } => {
  const editor = document.createElement('div');
  editor.classList.add('lfe-dsl-editor');

  // 行号
  const lineNumberArea = document.createElement('div');
  lineNumberArea.classList.add('lfe-dsl-editor-line-numbers');
  editor.appendChild(lineNumberArea);

  // 内容区域
  const contentArea = document.createElement('div');
  contentArea.classList.add('lfe-dsl-editor-content');
  editor.appendChild(contentArea);

  // 加载框
  const loadingMask = document.createElement('div');
  loadingMask.classList.add('lfe-dsl-editor-loading-mask');
  loadingMask.textContent = '加载中...';
  editor.appendChild(loadingMask);

  // 选框
  const selectLayer = document.createElement('div');
  selectLayer.classList.add('lfe-dsl-editor-select-layer');
  editor.appendChild(selectLayer);

  // tips层

  container.appendChild(editor);

  const removeLoadingMask = () => {
    if (loadingMask) {
      loadingMask.remove();
    }
  };

  return { editor, removeLoadingMask, contentArea };
};

/**
 * 打开资源
 * @param tokenService Token 服务
 * @param resourceId 资源ID
 * @returns 命令列表
 */
const openResource = async (tokenService: TokenService, resourceId?: string) => {
  const { resourceId: openedResourceId, commandList } = await tokenService.open(resourceId);
  if (!openedResourceId) {
    throw new Error('init editor failed, open resource failed');
  }
  if ((!commandList) || commandList.length === 0) {
    throw new Error('init editor failed, command list is empty');
  }
  return { openedResourceId, initCommandList: commandList };
};

/**
 * 初始化编辑器
 * @param tokenService Token 服务
 * @param container 容器元素
 * @param resourceId 资源ID
 */
export const editor = async (tokenService: TokenService, container: HTMLElement, resourceId?: string) => {
  const { removeLoadingMask, contentArea, editor } = createEditorDom(container);
  const { openedResourceId, initCommandList }= await openResource(tokenService, resourceId);

  const elementsStore = createElementsStore(contentArea);
  const focusNothing = () => {
    tokenService.send(openedResourceId, [{
      type: 'focusElement',
      location: undefined
    }]).then((commandList) => {
      applyCommandList(elementsStore, commandList);
    });
  }
  editor.addEventListener('click', () => {
    focusNothing();
  });
  contentArea.addEventListener('click', e => {
    e.stopPropagation();
  });

  elementsStore.registerDomFactory('input', (node: InputElement) => {
    const service = createInputService(openedResourceId, tokenService, elementsStore, node);
    const state = createInputState(service, node);
    return new DefaultDomController(state.createReadonlyInputDom());
  });
  elementsStore.registerDomFactory('label', (node: LabelElement) => {
    const label = document.createElement('div');
    label.classList.add('lfe-dsl-editor-label');
    label.textContent = node.label;
    return new DefaultDomController(label);
  });
  elementsStore.registerDomFactory('split', (node: SplitElement) => {
    const split = document.createElement('span');
    split.textContent = node.text;
    split.classList.add('lfe-dsl-editor-split');
    split.style.marginLeft = `${node.leftMargin}px`;
    split.style.marginRight = `${node.rightMargin}px`;
    return new DefaultDomController(split);
  });
  elementsStore.registerDomFactory('nextLine', (node: NextLineElement) => {
    const br = document.createElement('br');
    const indent = document.createElement('span');
    indent.classList.add('lfe-dsl-editor-next-line');
    indent.style.width = `${node.indent * 20}px`; // 假设每个缩进是20px
    return new NextLineDomController(br, indent);
  });
  elementsStore.registerDomFactory('context', (node: ContextElement) => {
    if (node.label) {
      const context = document.createElement('div');
      context.textContent = node.label;
      context.classList.add('lfe-dsl-editor-label');
      return new DefaultDomController(context);
    }
    return undefined;
  });
  applyCommandList(elementsStore, initCommandList);
  removeLoadingMask();
}

/**
 * 应用命令列表
 * @param elementsStore elements状态
 * @param commandList 命令列表
 */
const applyCommandList = (elementsStore: ElementsStore, commandList: Array<Command>): Position | undefined => {
  let contextStack: LinkedListNode<Element>[] = [];
  const getCurrentContext = () => {
    return contextStack.length === 0
      ? undefined
      : (contextStack[contextStack.length - 1].value as ContextElement);
  }
  let prev: LinkedListNode<Element> | undefined = undefined;
  let dom: HTMLElement | undefined = undefined;

  let currentPosition: Position | undefined = undefined;
  // 获取当前上下文
  commandList.forEach(command => {
    const name = command.command;
    switch (name) {
      case 'move': {
          currentPosition = {
            location: command.toLocation,
            offset: command.offset,
            moveToContext: command.moveToContext
          }
          const moveInContext = !!command.moveToContext;
          if (moveInContext) {
            contextStack = elementsStore.getNodesByLocation(currentPosition.location);
            const contextNode = contextStack[contextStack.length - 1];
            if (currentPosition.offset > 0) {
              prev = elementsStore.getChildAtOffset(contextNode?.value as (ContextElement | undefined), command.offset);
              dom = findLastDom(prev.value);
            } else {
              prev = undefined;
              if (contextNode && contextNode.prev) {
                dom = findLastDom(contextNode.prev.value);
              } else {
                dom = undefined;
              }
            }
          } else {
            const nodeList = elementsStore.getNodesByLocation(currentPosition.location);
            contextStack = nodeList.slice(0, -1);
            prev = elementsStore.offsetNode(nodeList[nodeList.length - 1], command.offset);
            dom = findLastDom(prev.value);
          }
        }
        break;
      case 'startContext': {
          const contextNode = elementsStore.appendElement({
            type: 'context',
            label: command.label,
            key: command.key,
            children: new LinkedList()
          }, getCurrentContext(), prev, dom);
          contextStack.push(contextNode);
          prev = undefined;

          const location = elementsStore.getElementLocation(contextNode.value);
          currentPosition = {
            location,
            moveToContext: true,
            offset: 0
          }
        }
        break;
      case 'endContext': {
          const context = contextStack.pop();
          if (!context) {
            throw new Error('apply command failed, context stack is empty');
          }
          prev = context;
          dom = findLastDom(context.value);

          const location = elementsStore.getElementLocation(context.value as ContextElement);
          currentPosition = { location, offset: 0 };
        }
        break;
      case 'createInput': {
          prev = elementsStore.appendElement({
            type: 'input',
            inputValue: command.inputValue,
            key: command.key
          }, getCurrentContext(), prev, dom);
          dom = prev.value.dom?.getLastDom();
          if (currentPosition) {
            currentPosition.offset += 1;
          }
        }
        break;
      case 'createLabel': {
          prev = elementsStore.appendElement({
            type: 'label',
            label: command.label,
          }, getCurrentContext(), prev, dom);
          dom = prev.value.dom?.getLastDom();
          if (currentPosition) {
            currentPosition.offset += 1;
          }
        }
        break;
      case 'createSplit': {
          prev = elementsStore.appendElement({
            type: 'split',
            text: command.text,
            leftMargin: command.leftMargin || 0,
            rightMargin: command.rightMargin || 0,
          }, getCurrentContext(), prev, dom);
          dom = prev.value.dom?.getLastDom();
          if (currentPosition) {
            currentPosition.offset += 1;
          }
        }
        break;
      case 'nextLine': {
          prev = elementsStore.appendElement({
            type: 'nextLine',
            indent: command.indent,
          }, getCurrentContext(), prev, dom);
          dom = prev.value.dom?.getLastDom();
          if (currentPosition) {
            currentPosition.offset += 1;
          }
        }
        break;
      case 'delete': {
          if (!currentPosition) {
            throw new Error('apply delete command failed, current position is undefined');
          }
          prev = elementsStore.removeElement(currentPosition, {
            start: command.range.start,
            end: command.range.end
          });
          dom = prev ? findLastDom(prev.value) : undefined;
        }
        break;
      default:
        throw new Error(`apply command failed, unknown command: ${name}`);
    }
  });
  return currentPosition;
}
